/**
 * rules 校验规则对象
 * {key：[rule]}
 * key：表单字段的名称
 * [rule]：校验规则数组
 * rule的值可以是内置的校验函数，也可以是自定义校验函数{name:String,validate:Function}，
 * 使用内置校验函数：
 * Validate.Required（） -- 非空
 * Validate.Email（） -- 邮箱
 * Validate.Phone（）-- 11位手机号
 * Validate.MinLength（number） -- 最小长度，接收一个number类型参数。
 * Validate.MaxLength（number） -- 最大长度，接收一个number类型参数。
 * Validate.Pattern（reg） -- 正则表达式校验，接收一个正则表达式类型参数。例： Validate.Pattern(/^[0-9]*$/)
 * Function时使用自定义校验规则，Function返回true表示校验通过，返回false表示校验未通过，函数传入一个参数，为表单字段的值。例(自定义校验最少5位)：(val)=>{ return val >= 5 }。
 * rule规则对象整体示例：
 *  创建校验对象
 * let validate = new Validate({ 
 *  loginId:[Validate.Required()],
 *  password:[Validate.Required(),{name:"minlength",(val)=>{ return val >= 5 }}],
 *  mobile:[Validate.Phone()],
 *  code:[Validate.MinLength(4)]
 * });
 * 手动校验
 * if(validate.UpdateValidate()){
 *  //校验通过
 * }else{
 *  //校验未通过
 * };
 * 
 * Validate对象的部分属性说明：
 * rules  对象 规则对象集合
 * * * * validates Array 当前字段的校验规则集合
 * * * * $valid  Boolean 当前字段是否通过校验
 * * * * validate Object<String,Boolean> 当前字段各项校验规则是否通过校验,key为校验规则的名称
 * * * * $dirty 当前字段是否校验过
 * $valid 布尔类型 表单校验是否通过
 * $dirty 表单是否未曾校验过，用来判断还未校验时不展示校验错误效果
 * */
export default class Validate {
    constructor(rules){
        for(let key in rules){
            this.rules[key] = {};
            if(rules[key].length>1){
                this.rules[key].validates = rules[key][1];
            }else{
                this.rules[key].validates = [];
            }
            this.rules[key].$valid = true;
            this.rules[key].validate = {};
            this.rules[key].$dirty = false;
            this.rules[key].default = rules[key][0];
            this.form[key] = rules[key][0];
        }
    }

    rules = {};
    $valid = true;
    $dirty = false;
    form = {};
    isReset = false;

    UpdateValidate(){
        let bool = true;
        if(this.form && this.rules){
            for(let key in this.rules){
                this.rules[key].$dirty = true;
                const validates = this.rules[key].validates;
                const value = this.form[key];
                const validate = {};
                let valid = true;
                if(validates && validates.length > 0){
                    validates.forEach(element => {
                        if(typeof element === 'object'){
                            validate[element.name] = element.validate(value);
                            if(!validate[element.name]){valid = false;}
                        }
                    });
                }
                this.rules[key].validate = validate;
                this.rules[key].$valid = valid;
                if(!valid){
                    bool = false;
                }
            }
        }
        this.$valid = bool;
        return bool;
    }

    static Required = ()=>{
        return new Required();
    }
    static Email = ()=>{
        return new Email();
    }
    static Phone = ()=>{
        return new Phone();
    }
    static MinLength = (val)=>{
        return new MinLength(val);
    }
    static MaxLength = (val)=>{
        return new MaxLength(val);
    }
    static Pattern = (val)=>{
        return new Pattern(val);
    }
    Validity(key){
        let valid = true;
        const rule = {...this.rules[key]};
        rule.validates.forEach(element => {
            if(typeof element === 'object'){
                rule.validate[element.name] = element.validate(this.form[key]);
                if(!rule.validate[element.name]){valid = false;}
            }
        });
        rule.$valid = valid;
        rule.$dirty = true;
        this.rules[key] = rule;
    }
    setValue(form){
        for(let key in this.form){
            if(form[key]){
                this.form[key] = form[key];
            }
        }
    }
    resetValue(){
        for(let key in this.rules){
            this.form[key] = this.rules[key].default;
        }
    }
    resetValid(){
        this.$valid = true;
        this.$dirty = false;
        for(let key in this.rules){
            this.rules[key].$valid = true;
            this.rules[key].validate = {};
            this.rules[key].$dirty = false;
        }
    }
}

class Required {
    name = 'required';
    constructor(){}
    validate(val){
        if(val !== undefined && val !== null && val !== ''){
            return true;
        }else{
            return false;
        }
    }
}
class Email {
    name = 'email';
    constructor(){}
    validate(val){
        if(val !== undefined && val !== null && val !== ''){
            return /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/.test(val);
        }else{
            return true;
        }
    }
}
    
class Phone {
    name = 'phone';
    constructor(){}
    validate(val){
        if(val !== undefined && val !== null && val !== ''){
            return /^(1[3-9][0-9])\d{8}$/.test(val);
        }else{
            return true;
        }
    }
} 
class MinLength {
    name = 'minlength';
    minlength = 0;
    constructor(number){
        this.minlength = number || 0;
    }
    validate(val){
        if(val !== undefined && val !== null && val !== ''){
            return val.length >= this.minlength;
        }else{
            return true;
        }
    }
}
class MaxLength {
    name = 'maxlength';
    maxlength = 0;
    constructor(number){
        this.maxlength = number || 99999;
    }
    validate(val){
        if(val !== undefined && val !== null && val !== ''){
            return val.length <= this.maxlength;
        }else{
            return true;
        }
    }
}
class Pattern {
    name = 'pattern';
    reg = null;
    constructor(reg){
        this.reg = reg;
    }
    validate(val){
        if(val !== undefined && val !== null && val !== ''){
            return this.reg.test(val);
        }else{
            return true;
        }
    }
}